package paim.wingchun.view;


import java.awt.BorderLayout;
import java.awt.Cursor;
import java.awt.Dimension;
import java.awt.Point;
import java.awt.event.MouseAdapter;
import java.beans.PropertyVetoException;
import java.util.List;

import javax.swing.ImageIcon;
import javax.swing.JComponent;
import javax.swing.JInternalFrame;
import javax.swing.JPanel;
import javax.swing.JToolBar;
import javax.swing.WindowConstants;

import com.jgoodies.uif_lite.panel.SimpleInternalFrame;

import paim.wingchun.app.Reflections;
import paim.wingchun.model.Recognizable;
import paim.wingchun.model.pojos.Erro;
import paim.wingchun.model.pojos.Pojo;
import paim.wingchun.view.componentes.panel.JPanelButtons;

/** @author paim 18/01/2011 */
@SuppressWarnings("serial")
public abstract class AbstractView<P extends Pojo> extends JInternalFrame implements Recognizable<P>, Editable {

    public enum Estado {
        Intocado, Confirmado, Alterado, Descartado;
    }

    private final Class<P> pClass;

    private boolean editando;

    protected void initialize() {
        Dimension d = new Dimension(500, 200);
        this.setSize(d);
        this.setMinimumSize(new Dimension(100, 80));
        this.setLocation(new Point(0, 0));
        this.setResizable(true);
        this.setDefaultCloseOperation(WindowConstants.DISPOSE_ON_CLOSE);
        this.setTitle("noname");
        this.setContentPane(getjInternalFrame());
        this.setFrameIcon(getIconJInternalFrame());
        // this.pack();
    }

    protected ImageIcon getIconJInternalFrame() {
        return GUIUtils.getImageIcon("icon.tabela." + getpClass().getSimpleName());
    }

    /** objeto atualmente na visao */
    private Object objetoReferencia;

    protected AbstractView(Class<P> pClass) {
        super("", false, true, true, true);
        this.pClass = pClass;
        initialize();

        this.repaint();
        // foco
        // ajuda
    }

    protected AbstractView() {
        super("", false, true, true, true);
        this.pClass = Reflections.getClassParameter(this.getClass(), Pojo.class);
        initialize();
        this.repaint();
    }

    @Override
    public final Class<P> getpClass() {
        return this.pClass;
    }

    /** busca objeto na visao */
    public final Object getObjeto() {
        try {
            antes_getObjeto();
            Object objeto = v_getObjeto();
            objeto = apos_getObjeto(objeto);
            return objeto;
        }
        catch ( Exception e ) {
            fechar();
        }
        return null;
    }

    protected void antes_getObjeto() {}

    protected abstract Object v_getObjeto() throws Exception;

    protected Object apos_getObjeto(Object objeto) {
        return objeto;
    }

    /** coloca esse objeto na visao, deve ser implementado na ponta do usuario */
    public final void setObjeto(Object objeto) {
        try {
            objeto = antes_setObjeto(objeto);

            setObjetoReferencia(objeto);
            // getProcessadorEventos().setObjeto(objeto);

            /* limpa visao antes de colocar outro objeto */
            vCleanErros();
            objeto = v_setObjeto(objeto);

            apos_setObjeto(objeto);
        }
        catch ( Exception e ) {
            e.printStackTrace();
            fechar();
        }
    }

    protected Object antes_setObjeto(Object objeto) {
        return objeto;
    }

    protected void apos_setObjeto(Object objeto) {}

    protected abstract Object v_setObjeto(Object objeto) throws Exception;

    /* TODO erros colocara o texto em vermelho piscante 3 vezes , ou adicionara o icone pxarope????? */
    /** apresenta erros na visao */
    public final void setErros(List<Erro> erros) {
        erros = antes_setErros(erros);
        v_setErros(erros);
        apos_setErros();
    }

    protected List<Erro> antes_setErros(List<Erro> erros) {
        return erros;
    }

    protected abstract void v_setErros(List<Erro> erros);

    protected void apos_setErros() {}

    // TODO poderia associar em um map, os componentes e seus atributos do pojo, para os erros?
    public abstract void vCleanErros();

    /** refresh erros visualmente
     *
     * @author paim 24/05/2011
     * @param erros
     *            void */
    public void refreshErros(List<Erro> erros) {
        vCleanErros();
        setErros(erros);
    }

    public void fechar() {
        antes_fechar();
        try {
            /* ira acionar oevento em listenerVisao */
            this.setClosed(true);
            apos_fechar();
        }

        catch ( PropertyVetoException e ) {
            e.printStackTrace();
        }
        finally {}
    }

    protected void antes_fechar() {}

    protected void apos_fechar() {}

    @Override
    public void setEditando(boolean editando) {
        this.editando = editando;
    }

    @Override
    public boolean isEditando() {
        return editando;
    }

    /** ################################################################ */

    // public ProcessadorEventos getProcessadorEventos() {
    // return processadorEventos;
    // }

    // public void setProcessadorEventos(ProcessadorEventos processadorEventos) {
    // this.processadorEventos = processadorEventos;
    // }

    // public void addListenerModificacaoEstado(PropertyChangeListener listener) {
    // getProcessadorEventos().addListener(listener);
    // }

    public JComponent getComponente(String nome) {
        JComponent componente = GUIUtils.getComponenteRecursivo(this, nome);
        return componente;
    }

    // TODO verificar se precisa setar nomes nesse caso,
    protected void setNomes() {}

    public abstract String getHelpId();

    public boolean getMaximized() {
        return true;
    }

    /** para de escutar o processador de eventos e seta cursor para wait
     *
     * @author paim 27/04/2011 void */
    public void freeze() {
        setCursor(Cursor.getPredefinedCursor(Cursor.WAIT_CURSOR));
    }

    /** restaura o processador de eventos e normaliza o cursor
     *
     * @author paim 27/04/2011 void */
    public void warmup() {
        setCursor(Cursor.getPredefinedCursor(Cursor.DEFAULT_CURSOR));
    }

    /** @author paim 28/04/2011 void */
    public boolean confirmaExclusao() {
        return Dialogs.pergunta(this, "Confirma exclusï¿½o");
    }

    /** TODO ...
     *
     * @author paim 29/04/2011 void */
    public boolean confirmaInclusao() {
        return false;
    }

    protected void setObjetoReferencia(Object objetoVisualizado) {
        this.objetoReferencia = objetoVisualizado;
    }

    public Object getObjetoReferencia() {
        return objetoReferencia;
    }

    private JPanel glassPanel;

    public JPanel getGlassPanel() {
        if ( glassPanel == null ) {
            glassPanel = new JPanel();
            glassPanel.setOpaque(false);
            glassPanel.setLayout(null);
            /* Associate dummy mouse listeners. Otherwise mouse events pass through */
            MouseAdapter fakeMouseAdapter = new MouseAdapter() {};
            glassPanel.addMouseListener(fakeMouseAdapter);
            glassPanel.addMouseWheelListener(fakeMouseAdapter);
            glassPanel.addMouseMotionListener(fakeMouseAdapter);
        }
        return glassPanel;
    }

    // #############################
    private JPanelButtons panelBotoes;

    /** @author paim 29/03/2011 */
    public JPanelButtons getjPanelBotoes() {
        if ( panelBotoes == null ) {
            panelBotoes = new JPanelButtons();
        }
        return panelBotoes;
    }

    private SimpleInternalFrame simpleInternalFrame;

    protected String getTituloSimpleInternalFrame() {
        return "";
    }

    protected SimpleInternalFrame getjInternalFrame() {
        if ( simpleInternalFrame == null ) {
            simpleInternalFrame = new SimpleInternalFrame("");
            simpleInternalFrame.setTitle(getTituloSimpleInternalFrame());
            simpleInternalFrame.setToolBar(getToolBar());
            simpleInternalFrame.add(getJPanelUsuario(), BorderLayout.CENTER);
            simpleInternalFrame.add(getjPanelBotoes(), BorderLayout.SOUTH);
        }
        return simpleInternalFrame;
    }

    protected abstract JToolBar getToolBar();

    /** O painel principal dessa window */
    protected abstract JPanel getJPanelUsuario();
}
